from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog
from PySide6.QtWidgets import QDialog, QTextEdit, QVBoxLayout
from PySide6.QtCore import QTimer, QElapsedTimer, QObject, QTranslator, QCoreApplication
from PySide6.QtGui import QIcon
from ui.main_ui import Ui_MainWindow
from controllers.storage_controller import StorageController
from controllers.stage_controller import StageController
from controllers.source_controller import SourceController
from drivers.motor_controller import MotorController
# from drivers.fake_motor_controller import FakeMotorController as MotorController
from drivers.source_meter import SourceMeterController
# from drivers.fake_source_meter import SourceMeterController
from utils.config_manager import ConfigManager
from utils.log_manager import logger
from utils.canvas import MatplotlibCanvas
from utils.scan_worker import ScanWorker

import numpy as np
import os
import sys
import datetime
import shutil

    
def resource_path(relative_path):
    """返回资源文件的绝对路径（兼容 PyInstaller 打包）"""
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath("."), relative_path)

class MainController(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowIcon(QIcon(resource_path("static/icon.ico")))
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # 子设置窗口
        self.storage_dialog = None
        self.stage_dialog = None
        self.source_dialog = None
        self._html_dialog = None

        # 初始化绘图画布（嵌入 graphicsView_plot 中）
        self.ui.canvas = MatplotlibCanvas(self.ui.graphicsView_plot)

        # ========== 在此处创建翻译器，并记到 self.translator ==========
        self.translator = QTranslator(self)

        # 设备控制器 & config
        self.config = ConfigManager()
        current_lang = self.config.get_language()    # 例如 "zh_CN"
        self._load_language(current_lang)            # 加载翻译

        # 设备控制器
        self.motor = MotorController()
        self.source = SourceMeterController()
        self.source.connect()
        self.config = ConfigManager()

        # 获取配置
        self.stage_x = self.config.get_stage_axis_config('x')
        self.stage_y = self.config.get_stage_axis_config('y')
        self.storage_config = self.config.get_storage_config()

        # 状态变量
        self.testing = False  # 是否正在测试
        self.paused = False   # 是否暂停中
        self._scan_ended = False
        self.total_points = 0
        self.tested_points = 0
        self.start_time = QElapsedTimer()
        self.elapsed_ms = 0
        self.data_map = None  # 用于绘图的数据矩阵
        self.worker = None    # 扫描线程对象
        self.new_data_flag = False  # 是否有新点数据
        self._remain_time_sec = 0  # 剩余时间（单位：秒）
        self.refresh_interval = max(int(self.storage_config.get("refresh_interval", 1)), 1)

        self._bind_buttons()      # 绑定 UI 事件
        self._init_motor()        # 初始化电机连接
        self._init_timers()       # 初始化状态刷新定时器
        self._update_scan_info()  # 计算并显示总点数等信息
    
    def _load_language(self, lang_code: str):
        """加载并安装语言翻译器，lang_code 如 'zh_CN'/'en_US'/'ko_KR'/'ja_JP'"""

        # 先卸载旧翻译器
        QCoreApplication.removeTranslator(self.translator)

        # 拼出 .qm 文件路径，比如放在 translations/ 下
        qm_file = resource_path(f"translations/{lang_code}.qm")

        # 加载 .qm 文件
        if self.translator.load(qm_file):
            QCoreApplication.installTranslator(self.translator)
        else:
            QMessageBox.warning(self, QCoreApplication.translate("MainController","提示"), QCoreApplication.translate("MainController","语言包 {qm_file} 加载失败！").format(qm_file=qm_file))
            return

        # 重新翻译UI
        self.ui.retranslateUi(self)
        # 如果其它对话框（storage_dialog等）已创建，也要调用它们的 retranslateUi() 或者重新刷新文字
        # 这里只是示例：如:
        # if self.storage_dialog is not None:
        #     self.storage_dialog.ui.retranslateUi(self.storage_dialog)
        if self.storage_dialog is not None:
            self.storage_dialog.ui.retranslateUi(self.storage_dialog)
        if self.stage_dialog is not None:
            self.stage_dialog.ui.retranslateUi(self.stage_dialog)
        if self.source_dialog is not None:
            self.source_dialog.ui.retranslateUi(self.source_dialog)
        self.ui.canvas.retranslate_canvas(lang_code)
        # 更新主窗口标题
        # self.setWindowTitle(QCoreApplication.translate("MainController","扫描成像软件"))
        #
        # 其余需要手动刷新字符串的地方，可以根据需要刷新

    def switch_language(self, lang_code: str):
        """切换语言并存到 config 中"""
        # 存到 config.ini
        self.config.set_language(lang_code)

        # 调用加载方法
        self._load_language(lang_code)

        logger.log(QCoreApplication.translate("MainController","语言已切换到：{lang_code}").format(lang_code=lang_code))


    def _bind_buttons(self):
        # 文件菜单 - 导入导出功能
        self.ui.action_export_data.triggered.connect(self._export_current_data)
        self.ui.action_import_data.triggered.connect(self._import_data)
        self.ui.action_export_image.triggered.connect(self._export_current_image)
        self.ui.action_export_config.triggered.connect(self._export_config)
        self.ui.action_import_config.triggered.connect(self._import_config)

        # 文件菜单 - 退出
        self.ui.action_exit.triggered.connect(self.close)

        # 帮助菜单 - 使用说明和关于
        self.ui.action_guide.triggered.connect(self._show_user_guide)
        self.ui.action_about.triggered.connect(self._show_about_info)

        # 设置类按钮绑定
        self.ui.btn_storage.clicked.connect(self.open_storage)
        self.ui.btn_stage.clicked.connect(self.open_stage)
        self.ui.btn_source.clicked.connect(self.open_source)
        self.ui.action_stage.triggered.connect(self.open_stage)
        self.ui.action_storage.triggered.connect(self.open_storage)
        self.ui.action_source.triggered.connect(self.open_source)

        # 测试控制类按钮绑定
        self.ui.btn_start.clicked.connect(self.start_test)
        self.ui.btn_pause.clicked.connect(self.pause_test)
        self.ui.btn_stop.clicked.connect(self.stop_test)

        # 初始化按钮状态
        self.ui.btn_pause.setEnabled(False)
        self.ui.btn_stop.setEnabled(False)

        # 语言菜单切换
        self.ui.actionChinese.triggered.connect(lambda: self.switch_language("zh_CN"))
        self.ui.actionEnglish.triggered.connect(lambda: self.switch_language("en_US"))
        self.ui.actionKorean.triggered.connect(lambda: self.switch_language("ko_KR"))
        self.ui.actionJapanese.triggered.connect(lambda: self.switch_language("ja_JP"))
    
    def _show_html_dialog(self, title: str, file_path: str):
        """读取 HTML 并展示成可滚动窗口"""
        try:
            real_path = resource_path(file_path)  # ✅ 使用资源路径函数
            with open(real_path, "r", encoding="utf-8") as f:
                html_content = f.read()

            dlg = QDialog(self)
            dlg.setWindowTitle(title)
            dlg.resize(600, 500)

            text_edit = QTextEdit()
            text_edit.setReadOnly(True)
            text_edit.setHtml(html_content)

            layout = QVBoxLayout(dlg)
            layout.addWidget(text_edit)

            dlg.setLayout(layout)
            dlg.show()
            self._html_dialog = dlg  # ✅ 保存引用以便语言切换时更新标题
        except Exception as e:
            QMessageBox.warning(self, QCoreApplication.translate("MainController","加载失败"), QCoreApplication.translate("MainController","无法读取文件：{e}").format(e=e))


    def _show_user_guide(self):
        current_lang = self.config.get_language()
        dlg_title=QCoreApplication.translate("MainController","使用说明")
        if current_lang == "en_US":
            html_file = "static/guide_en.html"
        elif current_lang == "ko_KR":
            html_file = "static/guide_ko.html"
        elif current_lang == "ja_JP":
            html_file = "static/guide_ja.html"
        else:
            html_file = "static/guide_zh.html"

        self._show_html_dialog(dlg_title, html_file)

    def _show_about_info(self):
        current_lang = self.config.get_language()
        dlg_title=QCoreApplication.translate("MainController","关于软件")
        if current_lang == "en_US":
            html_file = "static/about_en.html"
        elif current_lang == "ko_KR":
            html_file = "static/about_ko.html"
        elif current_lang == "ja_JP":
            html_file = "static/about_ja.html"
        else:
            html_file = "static/about_zh.html"

        self._show_html_dialog(dlg_title, html_file)


    def _init_motor(self):
        """连接电机并读取当前位置"""
        if self.motor.connect():
            x, y = self.motor.get_position_xy()
            self.ui.label_position_value.setText(f"X={x:.3f}, Y={y:.3f}")
            logger.log(QCoreApplication.translate("MainController","已连接电机，当前位置：X={x:.3f}, Y={y:.3f}").format(x=x, y=y))
        else:
            QMessageBox.critical(self, QCoreApplication.translate("MainController","错误"), QCoreApplication.translate("MainController","电机连接失败"))

    def _init_timers(self):
        """定时器用于定时刷新界面状态栏和图像"""
        self.timer = QTimer()
        self.timer.timeout.connect(self._update_status)
        self.timer.start(1000)  # 每秒刷新一次

    def _update_status(self):
        """更新运行时间与剩余时间，并根据设定频率刷新热力图"""
        if self.testing and not self.paused:
            self.elapsed_ms += 1000  # 每秒累加运行时间（ms）

            # 每秒自动递减剩余时间（不小于0）
            if self._remain_time_sec > 0:
                self._remain_time_sec -= 1

        # 更新时间显示
        time_s = self.elapsed_ms / 1000
        self.ui.label_runtime_value.setText(self._format_time(time_s))
        self.ui.label_remaining_time_value.setText(self._format_time(self._remain_time_sec))
        if self.motor.is_connected():
            x, y = self.motor.get_position_xy()
            self.ui.label_position_value.setText(f"X={x:.3f}, Y={y:.3f}")

        # 判断是否需要刷新热力图（整除秒数）
        if self.new_data_flag and int(time_s) % self.refresh_interval == 0:
            self._update_heatmap()
            self.new_data_flag = False

    def _format_time(self, seconds):
        """将秒数转换为 hh:mm:ss 字符串"""
        s = int(seconds)
        h, m, s = s // 3600, (s % 3600) // 60, s % 60
        return f"{h:02}:{m:02}:{s:02}"

    def _update_scan_info(self):
        """根据位移台设置计算总点数，并初始化数据矩阵"""
        dx = self.stage_x['end'] - self.stage_x['start']
        dy = self.stage_y['end'] - self.stage_y['start']
        steps_x = int(dx * 1000 / self.stage_x['step']) + 1
        steps_y = int(dy * 1000 / self.stage_y['step']) + 1
        self.total_points = steps_x * steps_y

        # UI 展示
        self.ui.label_measured_value.setText("0")
        self.ui.label_total_value.setText(str(self.total_points))

        # 初始化数据矩阵
        self.data_map = np.zeros((steps_y, steps_x))

    def _clear_heatmap(self):
        """清空热力图与绘图区域"""
        self.ui.canvas.axes.clear()
        self.ui.canvas.draw()

    def _reset_ui_and_config(self):
        """重置主页面内容，并从 config 重新加载配置"""
        self.config.reload()
        self.stage_x = self.config.get_stage_axis_config('x')
        self.stage_y = self.config.get_stage_axis_config('y')
        self.storage_config = self.config.get_storage_config()
        self.refresh_interval = max(int(self.storage_config.get("refresh_interval", 1)), 1)
        self._update_scan_info()
        self._init_motor()
        self.ui.label_source_value.setText("0.0000 A")
        self.ui.label_measured_value.setText("0")
        self.ui.label_runtime_value.setText("00:00:00")
        self.ui.label_remaining_time_value.setText("00:00:00")
        self._clear_heatmap()

    def _on_config_applied(self,is_storage=False):
        """当设置窗口点击“应用”后触发的同步动作"""
        self.config.reload()
        self.storage_config = self.config.get_storage_config()
        self.refresh_interval = max(int(self.storage_config.get("refresh_interval", 1)), 1)

        if is_storage:
            self._update_heatmap()
        elif not self.testing:
            self._reset_ui_and_config()
            logger.log(QCoreApplication.translate("MainController","⚙️ 配置更新已应用到主界面"))
        else:
            logger.log(QCoreApplication.translate("MainController","⚙️ 配置已保存，测试进行中，配置将部分生效"))

    def open_storage(self):
        """打开存储设置窗口"""
        # if self.testing:
        #     QMessageBox.warning(self, QCoreApplication.translate("MainController","提示"), QCoreApplication.translate("MainController","测试过程中修改设置下次测试生效"))
        if self.storage_dialog is None:
            self.storage_dialog = StorageController(self)
            self.storage_dialog.settings_applied.connect(lambda: self._on_config_applied(is_storage=True))
            self.storage_dialog.export_data_requested.connect(self._export_current_data)
            self.storage_dialog.export_image_requested.connect(self._export_current_image)
        self.storage_dialog.show()

    def open_stage(self):
        """打开位移台设置窗口"""
        if self.testing:
            QMessageBox.warning(self, QCoreApplication.translate("MainController","提示"), QCoreApplication.translate("MainController","测试过程中修改设置下次测试生效"))
        if self.stage_dialog is None:
            self.stage_dialog = StageController(self)
            self.stage_dialog.settings_applied.connect(self._on_config_applied)
        self.stage_dialog.show()

    def open_source(self):
        """打开源表设置窗口"""
        if self.testing:
            QMessageBox.warning(self, QCoreApplication.translate("MainController","提示"), QCoreApplication.translate("MainController","测试过程中修改设置下次测试生效"))
        if self.source_dialog is None:
            # ✅ 传入 self.source 实例
            self.source_dialog = SourceController(self, source=self.source)
            self.source_dialog.settings_applied.connect(self._on_config_applied)
        self.source_dialog.show()

    def start_test(self):
        """开始测试按钮触发的动作"""
        if not self.source.is_connected():
            QMessageBox.warning(self, QCoreApplication.translate("MainController","警告"), QCoreApplication.translate("MainController","源表未连接！"))
            return

        self._reset_ui_and_config()
        self.testing = True
        self.paused = False
        self._scan_ended = False
        self.tested_points = 0
        self.elapsed_ms = 0
        self._update_scan_info()
        self.start_time.start()

        self.ui.btn_start.setEnabled(False)
        self.ui.btn_pause.setEnabled(True)
        self.ui.btn_stop.setEnabled(True)

        if self.source_dialog is not None:
            self.source_dialog.apply_source_settings('a')


        self.source.output_on()
        logger.log(QCoreApplication.translate("MainController","🟢 开始扫描"))

        # 启动扫描线程
        self.worker = ScanWorker(
            motor=self.motor,
            source=self.source,
            stage_x=self.stage_x,
            stage_y=self.stage_y,
            testing_flag=lambda: self.testing,
            paused_flag=lambda: self.paused
        )
        self.worker.update_position.connect(self._on_position_update)
        self.worker.update_result.connect(self._on_result_update)
        self.worker.finished.connect(self._on_scan_finished)
        self.worker.start()

    def pause_test(self):
        """暂停/继续测试"""
        if not self.testing:
            return

        self.paused = not self.paused
        if self.paused:
            # 记录暂停前已耗时
            self.elapsed_ms += self.start_time.elapsed()
            self.ui.btn_pause.setText(QCoreApplication.translate("MainController","继续"))
            self.source.output_off()
            logger.log(QCoreApplication.translate("MainController","⏸️ 测试已暂停"))
        else:
            self.start_time.start()  # 恢复计时
            self.ui.btn_pause.setText(QCoreApplication.translate("MainController","暂停"))
            self.source.output_on()
            logger.log(QCoreApplication.translate("MainController","▶️ 测试继续"))

    def stop_test(self):
        """停止测试并重置界面状态"""
        self.testing = False
        self.paused = False
        self.source.output_off()
        self.ui.btn_start.setEnabled(True)
        self.ui.btn_pause.setEnabled(False)
        self.ui.btn_pause.setText(QCoreApplication.translate("MainController","暂停"))
        self.ui.btn_stop.setEnabled(False)
        logger.log(QCoreApplication.translate("MainController","🛑 测试已停止"))

    def _on_position_update(self, x, y):
        """线程回传位置更新"""
        self.ui.label_position_value.setText(f"X={x:.3f}, Y={y:.3f}")

    def _on_result_update(self, iy, ix, current):
        """线程回传电流采样数据"""
        self.ui.label_source_value.setText(f"{current:.4e} A")

        if self.data_map[iy, ix] == 0:  # 避免重复计数
            self.tested_points += 1
            self.ui.label_measured_value.setText(str(self.tested_points))

        self.data_map[iy, ix] = current
        self.new_data_flag = True

        # 重新校准剩余时间
        if self.tested_points > 0:
            avg_ms = self.elapsed_ms / self.tested_points
            remaining_points = self.total_points - self.tested_points
            self._remain_time_sec = int(avg_ms * remaining_points / 1000)

    def _on_scan_finished(self):
        """扫描完成信号处理"""
        if getattr(self, "_scan_ended", False):
            return  # 已经处理过了

        self._scan_ended = True  # 设置标志，表示已经处理过完成逻辑
        self.stop_test()
        self._export_current_data()
        self._export_current_image()

    def _update_heatmap(self):
        """刷新热力图，支持颜色条并防止图像被挤压"""
        from matplotlib import gridspec  # 只需导入一次即可

        cfg = self.storage_config
        vmin = float(cfg.get("vmin", -1))
        vmax = float(cfg.get("vmax", -1))
        cmap = cfg.get("color_map", "jet").lower()
        interpolation = cfg.get("interpolation_algorithm", "nearest")

        # 清除旧图（包括 colorbar），重新创建 subplot 结构
        self.ui.canvas.fig.clf()  # 清空整张图
        spec = self.ui.canvas.fig.add_gridspec(1, 2, width_ratios=[20, 1], wspace=0.1)
        ax_main = self.ui.canvas.fig.add_subplot(spec[0])
        ax_cbar = self.ui.canvas.fig.add_subplot(spec[1])

        imshow_args = {
            "cmap": cmap,
            "origin": "upper",
            "interpolation": interpolation,
            "aspect": "equal",
        }
        if vmin != -1:
            imshow_args["vmin"] = vmin
        if vmax != -1:
            imshow_args["vmax"] = vmax

        im = ax_main.imshow(self.data_map, **imshow_args)

        # 设置颜色条
        cbar = self.ui.canvas.fig.colorbar(im, cax=ax_cbar)
        cbar.set_label(QCoreApplication.translate("MainController","测量值"), fontsize=10)

        # 更新 canvas 引用
        self.ui.canvas.axes = ax_main
        self._colorbar = cbar

        self.ui.canvas.draw()


    def _export_current_image(self):
        """导出当前热力图为图片文件"""
        path = self.storage_config.get("image_path", "./result/pic")
        fmt = self.storage_config.get("image_format", "png").lower()
        prefix = "incomplete_" if self.tested_points < self.total_points else ""
        filename = prefix + datetime.datetime.now().strftime("heatmap_%Y%m%d_%H%M%S") + f".{fmt}"
        filepath = os.path.join(path, filename)

        try:
            os.makedirs(path, exist_ok=True)
            self.ui.canvas.fig.savefig(filepath, dpi=300, bbox_inches="tight")
            logger.log(QCoreApplication.translate("MainController","🖼️ 当前图像已保存到：{filepath}").format(filepath=filepath))
            QMessageBox.information(self, QCoreApplication.translate("MainController","导出成功"), QCoreApplication.translate("MainController","图像已成功保存到：\n{filepath}").format(filepath=filepath))
        except Exception as e:
            logger.log(QCoreApplication.translate("MainController","❌ 图像保存失败: {e}").format(e=e))
            QMessageBox.warning(self, QCoreApplication.translate("MainController","导出失败"), QCoreApplication.translate("MainController","保存图像失败：{e}").format(e=e))

    def _export_current_data(self):
        """根据配置导出当前数据矩阵为文件，支持多种格式，并保存当前配置"""
        path = self.storage_config.get("data_path", "./result/data")
        fmt = self.storage_config.get("file_format", "csv").lower()
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        prefix = "incomplete_" if self.tested_points < self.total_points else ""
        filename = f"{prefix}data_{timestamp}.{fmt}"
        filepath = os.path.join(path, filename)

        try:
            os.makedirs(path, exist_ok=True)
            if fmt == "csv":
                import pandas as pd
                pd.DataFrame(self.data_map).to_csv(filepath, index=False, header=False)
            elif fmt == "txt":
                np.savetxt(filepath, self.data_map, fmt="%.6e")
            elif fmt == "npy":
                np.save(filepath, self.data_map)
            elif fmt == "npz":
                np.savez(filepath, data=self.data_map)
            elif fmt == "xlsx":
                import pandas as pd
                pd.DataFrame(self.data_map).to_excel(filepath, index=False, header=False)
            elif fmt == "json":
                import json
                with open(filepath, "w", encoding="utf-8") as f:
                    json.dump(self.data_map.tolist(), f, indent=2)
            elif fmt in ["h5", "hdf5"]:
                import h5py
                with h5py.File(filepath, "w") as f:
                    f.create_dataset("data", data=self.data_map)
            elif fmt == "mat":
                from scipy.io import savemat
                savemat(filepath, {"data": self.data_map})
            else:
                raise ValueError(f"不支持的数据格式：{fmt}")

            # 同时保存配置文件副本
            config_copy_path = os.path.splitext(filepath)[0] + "_config.ini"
            shutil.copyfile("config.ini", config_copy_path)

            logger.log(QCoreApplication.translate("MainController","📄 当前数据已保存到：{filepath}\n📁 配置已保存到：{config_copy_path}").format(filepath=filepath, config_copy_path=config_copy_path))
            QMessageBox.information(self, QCoreApplication.translate("MainController","导出成功"), QCoreApplication.translate("MainController","数据和配置文件已保存到：\n{filepath}").format(filepath=filepath))

        except Exception as e:
            logger.log(QCoreApplication.translate("MainController","❌ 数据保存失败: {e}").format(e=e))
            QMessageBox.warning(self, QCoreApplication.translate("MainController","导出失败"), QCoreApplication.translate("MainController","保存数据失败：{e}").format(e=e))

    def _import_data(self):
        """导入数据文件，仅展示图像；如存在配置文件，用户选择恢复后再初始化状态准备继续测试"""
        file_path, _ = QFileDialog.getOpenFileName(self, QCoreApplication.translate("MainController","选择要导入的数据文件"))
        if not file_path:
            return

        try:
            # 1. 停止当前扫描（如有）
            if self.worker is not None and self.worker.isRunning():
                self.worker.terminate()
                self.worker.wait()
                logger.log(QCoreApplication.translate("MainController","🛑 已终止当前扫描线程"))

            self.testing = False
            self.paused = False
            self._scan_ended = True

            # 2. 加载数据文件
            ext = os.path.splitext(file_path)[1].lower()
            if ext == ".csv":
                import pandas as pd
                data = pd.read_csv(file_path, header=None).values
            elif ext == ".txt":
                data = np.loadtxt(file_path)
            elif ext == ".npy":
                data = np.load(file_path)
            elif ext == ".npz":
                data = np.load(file_path)["data"]
            elif ext == ".xlsx":
                import pandas as pd
                data = pd.read_excel(file_path, header=None).values
            elif ext == ".json":
                import json
                with open(file_path, "r", encoding="utf-8") as f:
                    data = np.array(json.load(f))
            elif ext in [".h5", ".hdf5"]:
                import h5py
                with h5py.File(file_path, "r") as f:
                    data = f["data"][:]
            elif ext == ".mat":
                from scipy.io import loadmat
                data = loadmat(file_path)["data"]
            else:
                raise ValueError(QCoreApplication.translate("MainController","不支持的数据格式"))

            if not isinstance(data, np.ndarray):
                raise ValueError(QCoreApplication.translate("MainController","读取的数据无效"))

            # 3. 展示图像（不做任何点数更新）
            self.data_map = data
            self._clear_heatmap()
            self._update_heatmap()

            logger.log(QCoreApplication.translate("MainController","📥 数据导入完成，仅用于图像展示"))

            # 清空点数和时间等状态显示
            self.ui.label_measured_value.setText("0")
            self.ui.label_total_value.setText(str(self.data_map.size))
            self.ui.label_runtime_value.setText("00:00:00")
            self.ui.label_remaining_time_value.setText("00:00:00")

            # 设置按钮状态为“不可测试”
            self.ui.btn_start.setEnabled(True)
            self.ui.btn_pause.setEnabled(False)
            self.ui.btn_pause.setText(QCoreApplication.translate("MainController","暂停"))
            self.ui.btn_stop.setEnabled(False)

            # 4. 检查是否有同名配置
            config_path = os.path.splitext(file_path)[0] + "_config.ini"
            if os.path.exists(config_path):
                reply = QMessageBox.question(
                    self,
                    QCoreApplication.translate("MainController","发现配置文件"),
                    QCoreApplication.translate("MainController","检测到同名配置文件，是否导入以恢复原设置？\n（将允许继续测试）"),
                    QMessageBox.Yes | QMessageBox.No
                )
                if reply == QMessageBox.Yes:
                    # 5. 用户同意恢复配置 → 初始化测试状态
                    shutil.copyfile(config_path, "config.ini")
                    self.config.reload()
                    self._on_config_applied()
                    self.data_map = data
                    self._update_heatmap()
                    # 计算点数和 tested_points
                    self.total_points = self.data_map.size
                    self.ui.label_total_value.setText(str(self.total_points))

                    nonzero_indices = np.argwhere(self.data_map != 0)
                    if nonzero_indices.size == 0 or nonzero_indices.size==self.data_map.size: #没测或全部测完，不存在继续测试
                        self.tested_points = 0
                        logger.log(QCoreApplication.translate("MainController","📊 数据导入完成，配置文件导入成功"))
                        QMessageBox.information(self, QCoreApplication.translate("MainController","导入成功"), QCoreApplication.translate("MainController","数据与配置已导入"))
                    else:
                        last_iy, last_ix = nonzero_indices[-1]
                        steps_y, steps_x = self.data_map.shape
                        self.tested_points = last_iy * steps_x + last_ix + 1

                        self.ui.label_measured_value.setText(str(self.tested_points))

                        # 初始化状态为“可继续测试”
                        self.testing = True
                        self.paused = True
                        self._scan_ended = False
                        self.elapsed_ms = 0
                        self.start_time.start()

                        # 启用按钮
                        self.ui.btn_start.setEnabled(False)
                        self.ui.btn_pause.setEnabled(True)
                        self.ui.btn_pause.setText(QCoreApplication.translate("MainController","继续"))
                        self.ui.btn_stop.setEnabled(True)

                        # 创建扫描线程（暂停状态）
                        self.worker = ScanWorker(
                            motor=self.motor,
                            source=self.source,
                            stage_x=self.stage_x,
                            stage_y=self.stage_y,
                            testing_flag=lambda: self.testing,
                            paused_flag=lambda: self.paused,
                            tested_points=self.tested_points
                        )
                        self.worker.update_position.connect(self._on_position_update)
                        self.worker.update_result.connect(self._on_result_update)
                        self.worker.finished.connect(self._on_scan_finished)
                        self.worker.start()

                        logger.log(QCoreApplication.translate("MainController","✅ 配置恢复完成，已准备继续测试（已完成 {tested_points} / {total_points}）").format(tested_points=self.tested_points, total_points=self.total_points))
                        QMessageBox.information(self, QCoreApplication.translate("MainController","配置恢复成功"), QCoreApplication.translate("MainController","已恢复配置，可点击“继续”完成测试"))
                else:
                    logger.log(QCoreApplication.translate("MainController","📊 用户选择不加载配置，仅用于查看图像"))
                    QMessageBox.information(self, QCoreApplication.translate("MainController","导入成功"), QCoreApplication.translate("MainController","数据已导入，仅用于图像查看"))
            else:
                logger.log(QCoreApplication.translate("MainController","📊 数据导入完成，无配置文件"))
                QMessageBox.information(self, QCoreApplication.translate("MainController","导入成功"), QCoreApplication.translate("MainController","数据已导入，可查看图像"))

        except Exception as e:
            logger.log(QCoreApplication.translate("MainController","❌ 数据导入失败: {e}").format(e=e))
            QMessageBox.warning(self, QCoreApplication.translate("MainController","导入失败"), QCoreApplication.translate("MainController","导入失败：{e}").format(e=e))

    def _import_config(self):
        """手动导入配置文件"""
        file_path, _ = QFileDialog.getOpenFileName(self, QCoreApplication.translate("MainController","选择配置文件"), filter=QCoreApplication.translate("MainController","INI文件 (*.ini)"))
        if not file_path:
            return
        try:
            shutil.copyfile(file_path, "config.ini")
            self.config.reload()
            self._on_config_applied()
            logger.log(QCoreApplication.translate("MainController","✅ 已导入配置文件：{file_path}").format(file_path=file_path))
            QMessageBox.information(self, QCoreApplication.translate("MainController","导入成功"), QCoreApplication.translate("MainController","配置文件已导入：\n{file_path}").format(file_path=file_path))
        except Exception as e:
            logger.log(QCoreApplication.translate("MainController","❌ 配置导入失败: {e}").format(e=e))
            QMessageBox.warning(self, QCoreApplication.translate("MainController","导入失败"), QCoreApplication.translate("MainController","配置导入失败：{e}").format(e=e))

    def _export_config(self):
        """手动导出当前配置文件"""
        file_path, _ = QFileDialog.getSaveFileName(self, QCoreApplication.translate("MainController","导出配置文件"), "config_copy.ini", QCoreApplication.translate("MainController","INI文件 (*.ini)"))
        if not file_path:
            return
        try:
            shutil.copyfile("config.ini", file_path)
            logger.log(QCoreApplication.translate("MainController","✅ 配置文件已导出到：{file_path}").format(file_path=file_path))
            QMessageBox.information(self, QCoreApplication.translate("MainController","导出成功"), QCoreApplication.translate("MainController","配置文件已保存到：\n{file_path}").format(file_path=file_path))
        except Exception as e:
            logger.log(QCoreApplication.translate("MainController","❌ 配置导出失败: {e}").format(e=e))
            QMessageBox.warning(self, QCoreApplication.translate("MainController","导出失败"), QCoreApplication.translate("MainController","配置导出失败：{e}").format(e=e))
